#include <mathematics/Random.h>

namespace ne
{
    const uint32_t Random::MAX_RAND_NUMBER = 0x7FFF;

    Random::Random()
        : mSeedType(RST_ANY),
          mSeed(1),
          mCurrentSeed(1)
    {
    }

    Random::Random(const Random &random)
        : mSeedType(random.mSeedType),
          mSeed(random.mSeed),
          mCurrentSeed(random.mCurrentSeed)
    {
    }

    Random& Random::operator = (const Random &random)
    {
        mSeedType = random.mSeedType;
        mSeed = random.mSeed;
        mCurrentSeed = random.mCurrentSeed;
        return *this;
    }

    void Random::setSeedType(const RandomSeedType rst)
    {
        mSeedType = rst;
    }

    RandomSeedType Random::getSeedType() const
    {
        return mSeedType;
    }

    void Random::setTimeSeed()
    {
        mSeed = time(0);
        mCurrentSeed = mSeed;
        setSeedType(RST_TIME);
    }

    void Random::setSeed(const uint32_t seed)
    {
        mSeed = seed;
        mCurrentSeed = mSeed;
        setSeedType(RST_SPECIFY);
    }

    uint32_t Random::getSeed() const
    {
        return mSeed;
    }

    uint32_t Random::getCurrentSeed() const
    {
        return mCurrentSeed;
    }

    int Random::randInt()
    {
        mCurrentSeed = mCurrentSeed * 214013L + 2531011L;
        return (mCurrentSeed >> 16) & MAX_RAND_NUMBER;
    }

    int Random::randInt(const int end)
    {
        if (end > 0)
        {
            return randInt() % (1 + end);
        }
        else
        {
            return - (randInt() % (1 - end));
        }
    }

    int Random::randInt(const int begin, const int end)
    {
        return randInt(end - begin) + begin;
    }

    real Random::randReal()
    {
        return (real)randInt() / (real)MAX_RAND_NUMBER;
    }

    real Random::randReal(const real end)
    {
        return randReal() * end;
    }

    real Random::randReal(const real begin, const real end)
    {
        return randReal(end - begin) + begin;
    }

    bool Random::randBool()
    {
        int res = randInt();
        if (res & 1)
        {
            return true;
        }
        return false;
    }

    Random::~Random()
    {
    }

    void Random::RandTimeSeed()
    {
        std::srand(time(0));
    }

    void Random::RandSeed(const uint32_t seed)
    {
        std::srand(seed);
    }

    int Random::RandInt()
    {
        return std::rand();
    }

    int Random::RandInt(const int end)
    {
        if (end > 0)
        {
            return Random::RandInt() % (1 + end);
        }
        else
        {
            return - (Random::RandInt() % (1 - end));
        }
    }

    int Random::RandInt(const int begin, const int end)
    {
        return Random::RandInt(end - begin) + begin;
    }

    real Random::RandReal()
    {
        return (real)Random::RandInt() / (real)RAND_MAX;
    }

    real Random::RandReal(const real end)
    {
        return Random::RandReal() * end;
    }

    real Random::RandReal(const real begin, const real end)
    {
        return Random::RandReal(end - begin) + begin;
    }

    bool Random::RandBool()
    {
        int res = Random::RandInt();
        if (res & 1)
        {
            return true;
        }
        return false;
    }
}
